package 笔记.集合;

import com.entity.TTreeNodeReq;
import com.entity.TTreeNodeReq2;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author CHL
 * @ClassName: Lambda表达式
 * @Description: TODO
 * @date 2023/3/20 14:54
 * @Version 1.0
 */
public class Lambda {

    public static void main(String[] args) {

        // 手写数据
        TTreeNodeReq req1 = new TTreeNodeReq();
        req1.setAge(1);
        req1.setAge2(3);
        req1.setTreeId(1L);
        req1.setName("1号");

        TTreeNodeReq req2 = new TTreeNodeReq();
        req2.setAge(2);
        req2.setAge2(2);
        req2.setTreeId(2L);
        req2.setName("2号");
        TTreeNodeReq req3 = new TTreeNodeReq();
        req3.setAge(18);
        req3.setAge2(1);
        req3.setTreeId(3L);
        req3.setName("2号");

        List<TTreeNodeReq> list = new ArrayList<>();
        list.add(req1);
        list.add(req3);
        list.add(req2);

        // 排序
        /* 注意:1.字符串数字类型排序会有问题，应转换为数字类型排序。字符串会根据ASCII码去排
         *     2.默认排序不判断非空
         * 语法： nullsFirst null值在数组前面
         *       nullsLast  null值在数组后面
         *       reversed   倒序
         **/
        // 根据年龄正序
        list = list.stream().sorted(Comparator.comparing(TTreeNodeReq::getAge)).collect(Collectors.toList());

        // 根据年龄非空倒序排列,null值在前面--reversed()倒排语法
        list = list.stream().sorted(Comparator.comparing(TTreeNodeReq::getAge, Comparator.nullsFirst(Integer::compareTo)).reversed())
                .collect(Collectors.toList());

        // 根据年龄非空正序排列
        list = list.stream().sorted(Comparator.comparing(TTreeNodeReq::getAge, Comparator.nullsFirst(Integer::compareTo))).collect(Collectors.toList());

        // 根据年龄正序排列，null值在后面；再根据年龄2字段逆序排列
        list = list.stream().sorted(Comparator.comparing(TTreeNodeReq::getAge, Comparator.nullsLast(Integer::compareTo))
                        .thenComparing(TTreeNodeReq::getAge2,Comparator.nullsFirst(Integer::compareTo)).reversed())
                .collect(Collectors.toList());

//      ----------分组----------------------------------------------------------
        // 根据某个字段作为key,另一个字段作为value返回
        Map<Long, String> listMap = list.stream().collect(Collectors.toMap(TTreeNodeReq::getTreeId, TTreeNodeReq::getName));
        // 根据某字段分组
        Map<String, List<TTreeNodeReq>> mapByOne = list.stream().collect(Collectors.groupingBy(TTreeNodeReq::getName));

        //分组后，统计每组中数据量
        Map<String, Long> count = list.stream().collect(Collectors.groupingBy(TTreeNodeReq::getName, Collectors.counting()));

        // 分组后，求出每组中某属性的平均值
        Map<String, Double> avg = list.stream().filter(i -> i.getName() != null).
                collect(Collectors.groupingBy(TTreeNodeReq::getName, Collectors.averagingDouble(TTreeNodeReq::getAge)));

        // 分组，某属性求和
        Map<String, Double> sum = list.stream().filter(i -> i.getName() != null).
                collect(Collectors.groupingBy(TTreeNodeReq::getName, Collectors.summingDouble(TTreeNodeReq::getAge)));

        Double collect2 = list.stream().collect(Collectors.summingDouble(TTreeNodeReq::getAge));

        //对求和的结果集进行从大到小排序
        Map<String, Double> finalMap = new LinkedHashMap<>();
        sum.entrySet().stream().sorted(Map.Entry.<String, Double>comparingByValue().reversed())
                .forEachOrdered(e -> finalMap.put(e.getKey(), e.getValue()));

        // 根据某字段分组后，通过join，拼接某字段
        Map<String, String> joinNewMap = list.stream().filter(i -> i.getName() != null)
                .collect(Collectors.groupingBy(TTreeNodeReq::getName,
                        Collectors.mapping(i -> i.getAge().toString(), Collectors.joining(", ", "Post titles: [", "]"))));
        // 2号 -> Post titles: [2号, 2号]
        // 1号 -> Post titles: [1号]

        // 转换分组结果List -> Set
        Map<String, Set<String>> namesByName = list.stream()
                .collect(Collectors.groupingBy(TTreeNodeReq::getName, Collectors.mapping(TTreeNodeReq::getName, Collectors.toSet())));

        // 两个条件分组
        Map<String, Map<Integer, List<TTreeNodeReq>>> mapByTwo = list.stream()
                .collect(Collectors.groupingBy(TTreeNodeReq::getName, Collectors.groupingBy(TTreeNodeReq::getAge)));

        // 使用java8 stream groupingBy 操作,按日期分组list,将List转化为name的List
        Map<String, List<Integer>> mapList = list.stream()
                .collect(Collectors.groupingBy(TTreeNodeReq::getName, Collectors.mapping(TTreeNodeReq::getAge, Collectors.toList())));


//    --------------其他使用方式 ------------------------------------------------------------

        /**
         *  findAny 和 findFirst 的区别
         *  findAny:效率更高，因为是多线程的寻找元素，但是返回的结果可能不同
         *  findFirst：效率相对findAny效率要低，因为是单线程一个个去寻找，每次返回的结果都是相同的，无条件下会返回流的第一个元素
         *  相同点：如果流为空，都会返回一个空的optional对象。
         *      使用orElse()方法可以new一个空对象避免NPE;
         *          例如： list.stream().filter(s -> s.getAge().equals(18)).findAny().orElse(new TTreeNodeReq());
         *        orElseGet()方法获取其他值， TTreeNodeReqDemo是继承于list里元素的，否则报错
         *         比如： list.stream().filter(s -> s.getAge().equals(18)).findAny().orElseGet(TTreeNodeReqDemo::new)
         *         比如2：TTreeNodeReqDemo demo = new TTreeNodeReqDemo(); 继承父类，实现get()方法，返回this。
         *               demo.setAddress("hahahahaha");
         *              list.stream().filter(s -> s.getAge().equals(19)).findAny().orElseGet(demo);
         *        orElseThrow()方法抛出异常
         *         比如运行异常：list.stream().filter(s -> s.getAge().equals(18)).findFirst().orElseThrow(RuntimeException::new);
         *
         */
        // 获取当前对象,集合为空可能得到对象为null,会NPE
        list.stream().filter(s -> s.getAge().equals(18)).findAny().get();
        list.stream().filter(s -> s.getAge().equals(18)).findFirst().get();
        // 无符合返回空对象
        TTreeNodeReq tTreeNodeReq1 = list.stream().filter(s -> s.getAge().equals(18)).findAny().orElse(new TTreeNodeReq());
        // 无符合取其他对象
        TTreeNodeReq tTreeNodeReq = list.stream().filter(s -> s.getAge().equals(19)).findAny().orElseGet(TTreeNodeReq2::new);
        // 无符合数据抛异常
        TTreeNodeReq tTreeNodeReq2 = list.stream().filter(s -> s.getAge().equals(18)).findFirst().orElseThrow(RuntimeException::new);

        // 集合取某个字段 返回 符号分隔的字符串
        String str = list.stream().filter(Objects::nonNull).map(TTreeNodeReq::getName).collect(Collectors.joining(","));

        // 对象集合某字段类型转换
        List<Long> collect = list.stream().map(a -> Long.valueOf(a.getAge())).collect(Collectors.toList());

        // 求和
        long sum1 = collect.stream().collect(Collectors.summingInt(Long::byteValue));
        long sum2 = collect.stream().collect(Collectors.summarizingLong(s -> s)).getSum();
        long sum3 = collect.stream().mapToLong(Long::byteValue).sum();

        // 集合某属性 年龄最大值
        TTreeNodeReq MAX = list.stream().max(Comparator.comparing(TTreeNodeReq::getAge)).get();
        // 年龄最小值
        TTreeNodeReq MIN = list.stream().min(Comparator.comparing(TTreeNodeReq::getAge)).get();

        // 类型集合直转
        List<String> collect1 = collect.stream().map(String::valueOf).collect(Collectors.toList());


        // 手动分页,skip（页码pageNum-1*页数pageSize）:从第几个元素开始前面数据舍弃，后面的所有数据返回，limit（页数） 取出前N个数据
        List<TTreeNodeReq> fenye = list.stream().skip(2).limit(2).collect(Collectors.toList());


        // List转换成map
        Map<Long, String> map = list.stream().collect(Collectors.toMap(TTreeNodeReq::getTreeId, TTreeNodeReq::getName));

        // 遇到key重复的，第二个数据覆盖第一个
        Map<String,TTreeNodeReq> userMap4 = list.stream().collect(Collectors.toMap(TTreeNodeReq::getName, Function.identity(),(value1, value2)->value2));

    }


    //将字符串中的多个字符构成的集合转换为对应的Stream的实例
    public static Stream<Character> fromStringToStream(String str) {//aa  bb  cc  bb
        ArrayList<Character> list = new ArrayList<>();
        for (Character c : str.toCharArray()) {
            list.add(c);
        }
        return list.stream();

    }

}
